package com.yun.zf.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yun.zf.common.admin.domain.SysMenu;
import com.yun.zf.common.admin.model.RouterVo;
import com.yun.zf.common.admin.model.sys.MenuAddMo;
import com.yun.zf.common.admin.model.sys.MenuEditMo;
import com.yun.zf.common.admin.model.sys.MenuSearchMo;
import com.yun.zf.common.constant.UserConstants;
import com.yun.zf.common.mapstruct.admin.SysMapper;
import com.yun.zf.common.utils.StringUtils;
import com.yun.zf.system.mapper.SysMenuMapper;
import com.yun.zf.system.mapper.SysRoleMenuMapper;
import com.yun.zf.system.security.utils.SecurityUtils;
import com.yun.zf.system.service.ISysMenuService;
import com.yun.zf.system.service.SysUserRoleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 菜单 业务层处理
 *
 * @author ruoyi
 */
@Service
@Slf4j
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {
    public static final String PREMISSION_STRING = "perms[\"{0}\"]";

    @Autowired
    private SysMenuMapper menuMapper;

    @Autowired
    private SysRoleMenuMapper roleMenuMapper;

    @Autowired
    private SysUserRoleService userRoleService;



    /**
     * 查询系统菜单列表
     *
     * @param menu 菜单信息
     * @return 菜单列表
     */
    @Override
    public List<Tree<String>> selectMenuList(MenuSearchMo menu, Long userId) {
        List<SysMenu> menuList = null;
        if ("all".equals(menu.getStatus())){
            menu.setStatus("");
        }
        menuList = menuMapper.selectMenuListByUserId(menu,userId);
        // 构建node列表
        List<TreeNode<String>> nodeList = CollUtil.newArrayList();
        nodeList = menuList.stream().map(menuMo -> {
            Map<String, Object> map = new HashMap<>();
            map.put("perms", menuMo.getPerms());
            map.put("path", menuMo.getPath());
            map.put("menuType", menuMo.getMenuType());
            map.put("icon", menuMo.getIcon());
            map.put("isFrame", menuMo.getIsFrame());
            map.put("status", menuMo.getStatus());
            map.put("remark", menuMo.getRemark());
            map.put("component", menuMo.getComponent());
            map.put("menuId", menuMo.getMenuId());
            if (menuMo.getParentId() == 0L) {
                // 获取树形节点
                map.put("treeNode", new String[]{});
            } else {
                // 查询当前节点的父节点的父节点信息
                SysMenu sysMenu = this.selectMenuById(menuMo.getParentId());
                if (sysMenu!=null){
                    if (sysMenu.getParentId() == 0L) {
                        map.put("treeNode", new String[]{menuMo.getParentId().toString()});
                    } else {
                        map.put("treeNode", new String[]{sysMenu.getParentId().toString(), menuMo.getParentId().toString()});
                    }
                }
            }
            TreeNode<String> treeNode = new TreeNode<String>().setId(menuMo.getMenuId().toString())
                    .setName(menuMo.getMenuName())
                    .setParentId(menuMo.getParentId().toString())
                    .setWeight(menuMo.getOrderNum())
                    .setExtra(map);
            return treeNode;
        }).collect(Collectors.toList());

        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        treeNodeConfig.setIdKey("key");
        treeNodeConfig.setNameKey("menuName");
        treeNodeConfig.setWeightKey("orderNum");
        // treeNodeConfig.setChildrenKey("children");
        // 最大递归深度
        treeNodeConfig.setDeep(3);

        List<Tree<String>> treeList = TreeUtil.build(nodeList, "0", treeNodeConfig,
                (treeNode, tree) -> {
                    tree.setId(treeNode.getId().toString());
                    tree.setParentId(treeNode.getParentId().toString());
                    tree.setName(treeNode.getName());
                    tree.setWeight(treeNode.getWeight());
                    // 扩展属性 ...
                    tree.putExtra("perms", treeNode.getExtra().get("perms"));
                    tree.putExtra("path", treeNode.getExtra().get("path"));
                    tree.putExtra("menuType", treeNode.getExtra().get("menuType"));
                    tree.putExtra("icon", treeNode.getExtra().get("icon"));
                    tree.putExtra("isFrame", treeNode.getExtra().get("isFrame"));
                    tree.putExtra("status", treeNode.getExtra().get("status"));
                    tree.putExtra("remark", treeNode.getExtra().get("remark"));
                    tree.putExtra("treeNode", treeNode.getExtra().get("treeNode"));
                    tree.putExtra("component", treeNode.getExtra().get("component"));
                    tree.putExtra("menuId", treeNode.getExtra().get("menuId"));


                });

        return treeList;
    }

    @Override
    public List<Tree<String>> menuList() {
        List<SysMenu> menuList =  this.getMenu();
        // 构建node列表
        List<TreeNode<String>> nodeList = CollUtil.newArrayList();
        nodeList = menuList.stream().map(menuMo -> {
            Map<String, Object> map = new HashMap<>();
            TreeNode<String> treeNode = new TreeNode<String>().setId(menuMo.getMenuId().toString())
                    .setName(menuMo.getMenuName())
                    .setParentId(menuMo.getParentId().toString())
                    .setWeight(menuMo.getOrderNum())
                    .setExtra(map);
            return treeNode;
        }).collect(Collectors.toList());

        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        treeNodeConfig.setIdKey("value");
        treeNodeConfig.setNameKey("label");
        treeNodeConfig.setDeep(2);

        List<Tree<String>> treeList = TreeUtil.build(nodeList, "0", treeNodeConfig,
                (treeNode, tree) -> {
                    tree.setId(treeNode.getId().toString());
                    tree.setParentId(treeNode.getParentId().toString());
                    tree.setName(treeNode.getName());
                    //tree.setWeight(treeNode.getWeight());
                });

        return treeList;
    }

    /**
     * 根据用户ID查询权限
     *
     * @param
     * @return 权限列表
     */
    @Override
    public Set<String> selectMenuPermsByUserId(Long userId) {
        Set<String> permsSet = new HashSet<>();
        //1:查询用户角色id
        List<Long> userRoleList = userRoleService.getRoleList(userId);
        if (userRoleList.size()>0){
            List<String> perms = menuMapper.selectMenuPermsByUserId(userRoleList);
            for (String perm : perms) {
                if (StringUtils.isNotEmpty(perm)) {
                    permsSet.addAll(Arrays.asList(perm.trim().split(",")));
                }
            }
        }
        return permsSet;
    }

    /**
     * 根据用户ID查询菜单
     *
     * @param userId 用户名称
     * @return 菜单列表
     */
    @Override
    public List<SysMenu> selectMenuTreeByUserId(Long userId) {
        List<SysMenu> menus = null;
        if (SecurityUtils.isAdmin(userId)) {
            menus = menuMapper.selectMenuTreeAll();
        } else {
            menus = menuMapper.selectMenuTreeByUserId(userId);
        }
        return getChildPerms(menus, 0);
    }

    /**
     * 根据角色ID查询菜单树信息
     *
     * @param roleId 角色ID
     * @return 选中菜单列表
     */
    public List<Integer> selectMenuListByRoleId(Long roleId) {
        return menuMapper.selectMenuListByRoleId(roleId);
    }

    /**
     * 构建前端路由所需要的菜单
     *
     * @param menus 菜单列表
     * @return 路由列表
     */
    @Override
    public List<RouterVo> buildMenus(List<SysMenu> menus) {
        List<RouterVo> routers = new LinkedList<RouterVo>();
        for (SysMenu menu : menus) {
            RouterVo router = new RouterVo();
            router.setHideInMenu("1".equals(menu.getVisible()));
            router.setName(menu.getMenuName());
            router.setPath(menu.getPath());
            router.setComponent(menu.getComponent());
            router.setIcon(menu.getIcon());
            // router.setRedirect();
            router.setWrappers(new String[0]);
            List<SysMenu> cMenus = menu.getChildren();
            if (!cMenus.isEmpty() && cMenus.size() > 0 && "M".equals(menu.getMenuType())) {
                // router.setRedirect("noRedirect");
                router.setRoutes(buildMenus(cMenus));
            }
            routers.add(router);
        }
        return routers;
    }

    /**
     * 构建前端所需要树结构
     *
     * @param menus 菜单列表
     * @return 树结构列表
     */
    @Override
    public List<SysMenu> buildMenuTree(List<SysMenu> menus) {
        List<SysMenu> returnList = new ArrayList<SysMenu>();
        for (Iterator<SysMenu> iterator = menus.iterator(); iterator.hasNext(); ) {
            SysMenu t = (SysMenu) iterator.next();
            // 根据传入的某个父节点ID,遍历该父节点的所有子节点
            if (t.getParentId() == 0) {
                recursionFn(menus, t);
                returnList.add(t);
            }
        }
        if (returnList.isEmpty()) {
            returnList = menus;
        }
        return returnList;
    }



    /**
     * 根据菜单ID查询信息
     *
     * @param menuId 菜单ID
     * @return 菜单信息
     */
    @Override
    public SysMenu selectMenuById(Long menuId) {
        QueryWrapper<SysMenu> menuQueryWrapper = new QueryWrapper<>();
        menuQueryWrapper.lambda().eq(SysMenu::getMenuId, menuId);
        return baseMapper.selectOne(menuQueryWrapper);
    }

    /**
     * 是否存在菜单子节点
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    @Override
    public boolean hasChildByMenuId(Long menuId) {
        QueryWrapper<SysMenu> menuQueryWrapper = new QueryWrapper<>();
        menuQueryWrapper.lambda().eq(SysMenu::getParentId,menuId);
       List<SysMenu> menuList = baseMapper.selectList(menuQueryWrapper);
        return menuList.size() > 0 ? true : false;
    }

    /**
     * 查询菜单使用数量
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    @Override
    public boolean checkMenuExistRole(Long menuId) {
        int result = roleMenuMapper.checkMenuExistRole(menuId);
        return result > 0 ? true : false;
    }

    /**
     * 新增保存菜单信息
     *
     * @param menu 菜单信息
     * @return 结果
     */
    @Override
    public int insertMenu(MenuAddMo menu) {
        SysMenu sysMenu =  SysMapper.INSTANCE.moToMenu(menu);
        sysMenu.setCreateTime(new Date());
        // 获取最后一个排序
       SysMenu lastMenu = getLastOrderMenu(sysMenu.getParentId());
        if (lastMenu==null){
            sysMenu.setOrderNum("0");
        }else {
            sysMenu.setOrderNum(String.valueOf(Integer.parseInt(lastMenu.getOrderNum())+1) );
        }
        return baseMapper.insert(sysMenu);
    }

    @Override
    public SysMenu getLastOrderMenu(Long parentId) {
        QueryWrapper<SysMenu> menuQueryWrapper = new QueryWrapper<>();
        menuQueryWrapper.lambda().eq(SysMenu::getParentId,parentId)
        .orderByDesc(SysMenu::getOrderNum);
       List<SysMenu> menus = baseMapper.selectList(menuQueryWrapper);
        if (menus.size()==0) {
            return  null;
        }
        return  menus.get(0);
    }

    /**
     * 修改保存菜单信息
     *
     * @param menu 菜单信息
     * @return 结果
     */
    @Override
    public int updateMenu(MenuEditMo menu) {
        QueryWrapper<SysMenu> menuQueryWrapper = new QueryWrapper<>();
        menuQueryWrapper.lambda().eq(SysMenu::getMenuId, menu.getMenuId());
        SysMenu sysMenu=  baseMapper.selectOne(menuQueryWrapper);
        sysMenu.setMenuName(menu.getMenuName());
        sysMenu.setMenuType(menu.getMenuType());
        sysMenu.setComponent(menu.getComponent());
        sysMenu.setPath(menu.getPath());
        sysMenu.setIcon(menu.getIcon());
        sysMenu.setOrderNum(menu.getOrderNum());
        sysMenu.setIsFrame(menu.getIsFrame());
        sysMenu.setStatus(menu.getStatus());
        sysMenu.setVisible(menu.getVisible());
        sysMenu.setUpdateTime(new Date());
        sysMenu.setRemark(menu.getRemark());
        sysMenu.setPerms(menu.getPerms());
        return baseMapper.update(sysMenu, menuQueryWrapper);
    }

    /**
     * 删除菜单管理信息
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    @Override
    public int deleteMenuById(Long menuId) {
        QueryWrapper<SysMenu> menuQueryWrapper = new QueryWrapper<>();
        menuQueryWrapper.lambda().eq(SysMenu::getMenuId,menuId);
        return baseMapper.delete(menuQueryWrapper);
    }

    /**
     * 校验菜单名称是否唯一
     *
     * @param
     * @return 结果
     */
    @Override
    public String checkMenuNameUnique(Long menuId,String menuName) {

        QueryWrapper<SysMenu> menuQueryWrapper = new QueryWrapper<>();
        menuQueryWrapper.lambda().eq(SysMenu::getMenuName, menuName);
       SysMenu info = baseMapper.selectOne(menuQueryWrapper);
        if (StringUtils.isNotNull(info) && info.getMenuId().longValue() != menuId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }


    /**
     * 根据父节点的ID获取所有子节点
     *
     * @param list     分类表
     * @param parentId 传入的父节点ID
     * @return String
     */
    public List<SysMenu> getChildPerms(List<SysMenu> list, int parentId) {
        List<SysMenu> returnList = new ArrayList<SysMenu>();
        for (Iterator<SysMenu> iterator = list.iterator(); iterator.hasNext(); ) {
            SysMenu t = (SysMenu) iterator.next();
            // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点
            if (t.getParentId() == parentId) {
                recursionFn(list, t);
                returnList.add(t);
            }
        }
        return returnList;
    }

    /**
     * 递归列表
     *
     * @param list
     * @param t
     */
    private void recursionFn(List<SysMenu> list, SysMenu t) {
        // 得到子节点列表
        List<SysMenu> childList = getChildList(list, t);
        t.setChildren(childList);
        for (SysMenu tChild : childList) {
            if (hasChild(list, tChild)) {
                // 判断是否有子节点
                Iterator<SysMenu> it = childList.iterator();
                while (it.hasNext()) {
                    SysMenu n = (SysMenu) it.next();
                    recursionFn(list, n);
                }
            }
        }
    }

    /**
     * 得到子节点列表
     */
    private List<SysMenu> getChildList(List<SysMenu> list, SysMenu t) {
        List<SysMenu> tlist = new ArrayList<SysMenu>();
        Iterator<SysMenu> it = list.iterator();
        while (it.hasNext()) {
            SysMenu n = (SysMenu) it.next();
            if (n.getParentId().longValue() == t.getMenuId().longValue()) {
                tlist.add(n);
            }
        }
        return tlist;
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<SysMenu> list, SysMenu t) {
        return getChildList(list, t).size() > 0 ? true : false;
    }


    @Override
    public List<SysMenu> getMenu() {
        QueryWrapper<SysMenu> menuQueryWrapper = new QueryWrapper<>();
        menuQueryWrapper.lambda().eq(SysMenu::getStatus,"0");
        return baseMapper.selectList(menuQueryWrapper);
    }
}
